package com.spsoft.vatoutinv.service.official.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.spsoft.core.enums.ResponseEnum;
import com.spsoft.core.exception.BusinessException;
import com.spsoft.core.model.Result;
import com.spsoft.core.utils.BeanUtils;
import com.spsoft.core.utils.StringUtil;
import com.spsoft.system.entity.NvatNegativestream;
import com.spsoft.system.model.bo.official.InvoiceDownloadBo;
import com.spsoft.system.model.bo.official.InvoiceQueryBo;
import com.spsoft.system.model.vo.official.*;
import com.spsoft.system.service.*;
import com.spsoft.vatoutinv.config.InterfaceProperties;
import com.spsoft.vatoutinv.config.Sm4Properties;
import com.spsoft.vatoutinv.entity.vmsfullbswjmanager.VmsFullBswjManager;
import com.spsoft.vatoutinv.enums.CommonEnum;
import com.spsoft.vatoutinv.service.official.OfficialDealInvoiceService;
import com.spsoft.vatoutinv.service.official.OfficialInvoiceService;
import com.spsoft.vatoutinv.service.vmsfullbswjmanager.VmsFullBswjManagerService;
import com.spsoft.vms.redis.RedisService;
import com.spsoft.vms.redis.constant.RedisConstant;
import com.spsoft.vms.redis.service.BswjRedisService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 官网-查询开票接口业务逻辑处理接口实现类
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class OfficialInvoiceServiceImpl implements OfficialInvoiceService {
    private final OfficialDealInvoiceService officialDealInvoiceService;
    /**
     * 交易数据信息表
     */
    private final NvatTrandtadvaltaxsepService nvatTrandtadvaltaxsepService;

    /**
     * 应用参数配置
     */
    private final BiDataConfigInfoService biDataConfigInfoService;

    /**
     * 负数流水管理
     */
    private final NvatNegativestreamService negativestreamService;

    /**
     * 校验是否有电子发票试点资质
     */
    private final NvatChoiceofunitextService nvatChoiceofunitextService;

//    private final VmsEnterpriseInfoService vmsEnterpriseInfoService;
    /**
     * 版式文件服务缓存，查询是否有数电票开具资质
     */
    private final BswjRedisService bswjRedisService;
    /**
     * 企业商品及服务
     */
//    private final VmsEpsInformationService epsInformationService;

    /**
     * 版式文件管理
     */
    private final VmsFullBswjManagerService vmsFullBswjManagerService;

    /**
     * 开票接口
     */
//    private final IssueInvoiceService issueInvoiceService;

    /**
     * 发票主表信息
     */
    private final NvatOutinvoicedetailsService nvatOutinvoicedetailsService;
//    /**
//     * 发票明细
//     */
//    private final NvatOutInvoiceItemsMapper nvatOutInvoiceItemsMapper;
//    private final SequenceService sequenceService;
//    /**
//     * 流水发票关联关系
//     */
//    private final NvatRevmapinvoitemsService nvatRevmapinvoitemsService;
//    /**
//     * 老系统的企业商品及服务信息
//     */
//    private final NvatSxcpbXinhuaService nvatSxcpbXinhuaService;
    private final RedisService redisService;
    private final InterfaceProperties interfacesProperties;

    private final Sm4Properties sm4Properties;

    @Override
    public List<InvoiceQueryVO> invoiceQuery(InvoiceQueryBo dto) {
        /**
         * 0. 校验接入账号
         * 1、查询交易流水表，得到交易流水数据List
         * 2、根据流水id查询发票信息Map
         * 3、根据发票信息查询电子发票的下载地址Map
         * 4、 过滤数据：
         * （1）每个交易日期是一条返回数据
         * （2）电子发票：
         *      交易金额累加
         *      当日所有流水状态都=3，且存在下载地址，则kpbs=1
         *      否则kpbs=0
         * （3）纸质发票
         *      流水状态=3，交易金额累加，且开票标识=2
         *      流水状态!=3，交易金额累加，且开票标识=0
         *  (5) 数电票逻辑：
         * 5、同一天的数据，若流水的开票标识不一样，开票标识=2的单独处理，其他数据当天的开票标识置为0, 且数据合并
         */
        validJrzhJrmm(dto.getJrzh(), dto.getJrmm());

        // 查询交易流水数据
        List<InvoiceFlowQueryVO> flowList = nvatTrandtadvaltaxsepService.queryByYwbh(dto);
        if (CollectionUtil.isEmpty(flowList)) {
            return null;
        }

        // 交易机构，查询发票下载地址用
        String jyjg = flowList.get(0).getJYJG();
        // 纳税人识别号，拼接电子发票的下载地址用
        String nssbh = nvatTrandtadvaltaxsepService.queryNssbhByJyjg(jyjg);
        String dzfpUrlPrefix = biDataConfigInfoService.getEDonwloadUrlPrefix();

        // 流水id，查询发票信息用
        List<Long> rdidList = flowList.stream().map(InvoiceFlowQueryVO::getRDID).collect(Collectors.toList());
        // 根据流水id，查询发票信息
        List<InvoiceInfoVO> invoiceInfoList = nvatOutinvoicedetailsService.queryInvoiceBYRdids(rdidList);
        Map<Long, InvoiceInfoVO> invoiceInfoMap = new HashMap<>();
        if (CollectionUtil.isNotEmpty(invoiceInfoList)) {
            invoiceInfoMap = invoiceInfoList.stream().collect(Collectors.toMap(InvoiceInfoVO::getRDID, vo -> vo, (key1, key2) -> key2));
        }

        // 定义返回值map
        Map<Date,Map<String,InvoiceQueryVO>> resultMap = new HashMap<>();

        // 循环流水列表，过滤、组装返回结果
        for (InvoiceFlowQueryVO flowVO : flowList) {
            // 流水状态 1-未开票  3-全部开票
            InvoiceInfoVO infoVO = invoiceInfoMap.get(flowVO.getRDID());
            String dzfpurl = "";
            if (infoVO != null && StringUtils.isNotBlank(dzfpUrlPrefix)) {
                dzfpurl = OfficialServiceCommonMtd.getDzfpUrl(dzfpUrlPrefix, infoVO.getFPDM(), infoVO.getFPHM(), nssbh);
            }
            convertToInvoiceQueryVO(resultMap, infoVO, flowVO, dzfpurl, nssbh);
        }

        // 同一天的数据，若流水的开票标识不一样，开票标识=2的单独处理，其他数据当天的开票标识置为0, 且数据合并
        mergeJyrqData(resultMap);
        // 数电票地址去重
        resultMap.forEach((k,v) -> {
            InvoiceQueryVO vo = v.get("1");
            if (vo != null && vo.getSdpXzdzList() != null) {
                List<SdpXzdzVO> unique = vo.getSdpXzdzList().stream().distinct().collect(Collectors.toList());
                vo.setSdpXzdzList(unique);
            }
        });
        // map转为返回结果list
        List<InvoiceQueryVO> resultList = resultMap.entrySet().stream()
                .flatMap(e -> e.getValue().values().stream())
                .collect(Collectors.toList());
        return resultList;
    }


    @Override
    public Result<InvoiceDownloadVO> invoiceDownload(InvoiceDownloadBo bo) {
        /**
         * 0. 校验接入账号
         * 1. 查询负数流水管理表，未处理状态如果存在数据，则不可开票
         * 2. 查询交易流水信息，结果如果为空，则 4003 没有能找到对应的流水（无此保单相关信息）
         *    补充逻辑：非自然人流水不能开票。
         * 3. 电子发票试点、数电票能力校验，二者都没有，则不能开票
         * 4. 交易流水状态=3, 查询待开票信息（则根据流水rdid查询发票信息（查询条件限制流水状=3），如果发票号码和发票代码都为空，则是待开票），
         *  (A). 如果存在待开票，则返回错误码，不得开票
         *  (B). 如果不存在待开票信息，
         *  （1）存在发票信息
         *      026：电子发票，则拼装电子发票地址
         *      01/02：数电票，则拼装数电票地址
         *      07/04：已开纸质发票，不能下载，
         *   (3)不存在发票信息，非正常逻辑数据，不能开票，当做纸质票返回
         *  （4）如果只有纸质发票，且不能开具电子发票、数电票，则提示 保单合同已开具纸质发票
         * 5. 交易流水状态=1的数据列表进行开票： 有数电票能力优先数电票，无数电票能力则调用电子发票平台开电子发票。
         * ①4004 2017年1月1日之前的流水不能开具电子发票
         * ②根据交易日期，合并交易流水数据，合并后，校验JYRMBJE字段：
         *      如果JYRMBJE=0,则 7001 流水已抵消无需开票！
         *      如果JYRMBJE<0，则提示 7002 原流水已开票，请到柜台处理！
         * ③查询交易流水+寿险表，得到发票明细数据，并根据sl进行合并
         * ④调用电子发票平台接口开票
         * 6. 返回值中拼装发票地址
         * 7.更新数据库
         *    更新交易流水表，LSZT=3
         *    保存发票主表、
         *    保存发票明细表、
         *    保存流水关联表
         *    （负数管理表需要处理数据定义：根据rdid查询到未处理的数据（业务编号未查到这些数据））
         *    修改负数流水表：处理状态=0（未处理）的数据，处理状态=1（已处理）、处理类型=5（负数流水开票）、处理人=官网开票、处理时间=当前日期、处理说明=官网开票
         */
        CommonEnum datasource = validJrzhJrmm(bo.getJrzh(), bo.getJrmm());

        InvoiceDownloadVO downloadVO =  new InvoiceDownloadVO();
        Set<String> dzfpxzUrls = new HashSet<>();
        List<SdpXzdzVO> sdpXzdzVOS = new ArrayList<>();
        downloadVO.setDzfpXzdz(dzfpxzUrls);
        downloadVO.setSdpXzdzList(sdpXzdzVOS);

        // 1. 查询负数流水管理表，未处理状态如果存在数据，则不可开票
        List<NvatNegativestream> negativestreamList = negativestreamService.getByClztYwbh(bo.getYwbh());
        if (CollectionUtil.isNotEmpty(negativestreamList)) {
            return Result.ERROR(ResponseEnum.OFFICIAL_DZFPPT_HAS_NEGFLOW_ERROR);
        }

        String LOG_MSG = datasource.getValue();

        String redisLockKey = String.format(RedisConstant.REDIS_OFFICIAL_LOCK_KEY, bo.getYwbh());
        RLock lock = redisService.getLock(redisLockKey);
        boolean success = redisService.tryLock(lock, 1, 500);
        if (!success) {
            log.info("{}尝试指定次数后均未获取到锁，返回系统繁忙。key：{}", LOG_MSG, redisLockKey);
            return Result.ERROR(ResponseEnum.REDIS_LOCK_NO_GET);
        }
        log.info("{}redisson上锁成功，key：{}", LOG_MSG, redisLockKey);

        try {
            // 2. 查询交易流水信息 如果结果如果为空，则 没有能找到对应的流水（无此保单相关信息）
            List<TransactionFlowVO> transactionFlowVOS = nvatTrandtadvaltaxsepService.queryByJyrqYwbh(bo.getJyrq(), bo.getYwbh());
            if (CollectionUtil.isEmpty(transactionFlowVOS)) {
                return Result.ERROR(ResponseEnum.OFFICIAL_DZFPPT_NOFLOW_ERROR);
            }
            // 个人业务标志，非自然人业务不能开票
            List<TransactionFlowVO> notGrywList = transactionFlowVOS.stream()
                    .filter(flow -> StringUtil.isNotBlank(flow.getISGRYW()) && !"是".equals(flow.getISGRYW()))
                    .collect(Collectors.toList());
            boolean notGryw = CollectionUtil.isNotEmpty(notGrywList);
            if (notGryw) {
                return Result.ERROR(ResponseEnum.OFFICIAL_NOT_GRYW_ERROR);
            }
            // 3.电子发票试点、数电票能力校验，二者都没有，则不能开票
            String jyjg = transactionFlowVOS.get(0).getJYJG();
            boolean sdpzz = false;
            VmsFullBswjManager bswj = null;
            try {
                bswj = vmsFullBswjManagerService.getOneByWhjg(jyjg); // 版式文件
                if (bswj != null) {
                    sdpzz = "01".equals(bswj.getQyzt()) && "Y".equals(bswj.getFpkjzt());
                }
            } catch (BusinessException be) {
                log.error("{}查询版式文件数据，业务异常，业务编号：{}，交易机构：{}, code:{}, msg:{}",
                        datasource.getValue(), bo.getYwbh(), jyjg, be.getCode(), be.getMsg());
            }
            boolean sdpqx = sdpzz && StringUtil.isNotEmpty(bswj.getJkkpkpr()) && StringUtil.isNotEmpty(bswj.getQydm());
//            boolean sdpqx = false;

            boolean dzfpzz = false; // 电子发票试点能力
            if (!sdpqx) {
                dzfpzz = nvatChoiceofunitextService.querySFQYDZFPByjyjg(jyjg);
            }
            if (!sdpqx && !dzfpzz) {
                return Result.ERROR(ResponseEnum.OFFICIAL_NO_AUTH_ERROR);
            }

            // 4. 交易流水状态=3,
            Map<Integer, List<TransactionFlowVO>> lsztMap = transactionFlowVOS.stream().collect(Collectors.groupingBy(TransactionFlowVO::getLSZT));
            List<TransactionFlowVO> ykpFlowList = lsztMap.get(3);
            List<TransactionFlowVO> wkpFlowList = lsztMap.get(1) == null ? new ArrayList<>() : lsztMap.get(1);
            List<InvoiceInfoVO> paperInvoiceList = new ArrayList<>();

            // 处理已开票流水数据
            if (CollectionUtil.isNotEmpty(ykpFlowList)) {
                List<InvoiceInfoVO> ykpInvoiceList = this.dealYkpFlowList(ykpFlowList);
                // 交易流水为已开票状态，但查不到发票信息, 且未开票状态交易流水为空，则返回错误
                if (CollectionUtil.isEmpty(ykpInvoiceList) && CollectionUtil.isEmpty(wkpFlowList)) {
                    return Result.ERROR(ResponseEnum.OFFICIAL_INVOICE_NOTFOUND_ERROR);
                }
                // 纳税人识别号，拼接电子发票的下载地址用
                String nssbh = nvatTrandtadvaltaxsepService.queryNssbhByJyjg(jyjg);
                String dzfpUrlPrefix = biDataConfigInfoService.getEDonwloadUrlPrefix();
                if (CollectionUtil.isNotEmpty(ykpInvoiceList)) {
                    ykpInvoiceList.forEach(v -> {
                        if (CommonEnum.INVOICE_TYPE_026.getKey().equals(v.getFPLXDM())) { // 电子发票
                            if(StringUtil.isBlank(nssbh)){
                                throw new BusinessException(ResponseEnum.OFFICIAL_NO_AUTH_ERROR1);
                            }
                            String dzfpurl = OfficialServiceCommonMtd.getDzfpUrl(dzfpUrlPrefix, v.getFPDM(), v.getFPHM(), nssbh);
                            dzfpxzUrls.add(dzfpurl);
                        } else if (CommonEnum.INVOICE_TYPE_01.getKey().equals(v.getFPLXDM()) || CommonEnum.INVOICE_TYPE_02.getKey().equals(v.getFPLXDM())) { // 数电票
//                            sdpXzdzVOS.add(this.getSdpXzdzVO(v.getFPHM()));
                            SdpXzdzVO dz = OfficialServiceCommonMtd.getSdpXzdzVO(v.getFPHM(), interfacesProperties.getSdpDownloadUrlPrefix(), sm4Properties.getKey().getBytes());
                            sdpXzdzVOS.add(dz);
                        } else { // 纸质票
                            paperInvoiceList.add(v);
                        }
                    });
                }
            }

            // 没有未开票的流水，直接返回结果。
            if (CollectionUtil.isEmpty(wkpFlowList)) {
                if (CollectionUtil.isNotEmpty(paperInvoiceList)
                        && CollectionUtil.isEmpty(downloadVO.getDzfpXzdz())
                        && CollectionUtil.isEmpty(downloadVO.getSdpXzdzList())) {
                    return Result.ERROR(ResponseEnum.OFFICIAL_ONLY_PAPER_ERROR);
                }
                return OfficialServiceCommonMtd.uniqueSdpList(downloadVO);
            }

            // 以下：处理未开票流水数据
            // ①4004 2017年1月1日之前的流水不能开具电子发票
            if (Long.parseLong("20170101") > Long.parseLong(bo.getJyrq())) {
                return Result.ERROR(ResponseEnum.OFFICIAL_DZFPPT_OLD_DATA_ERROR);
            }
            // * ②根据交易日期，合并交易流水数据，合并后，校验JYRMBJE字段：
            TransactionFlowVO transactionFlowMerge = this.getTransactionFlowMerge(wkpFlowList);
            this.dealJYRMBJE(transactionFlowMerge,wkpFlowList);

            // 调用数电票接口
            if (sdpqx) {
                return officialDealInvoiceService.dealSdpResult(transactionFlowMerge, wkpFlowList, bswj, datasource, downloadVO);
            }

            // **********如果不是数电票，则调用电子发票平台接口************
            if (dzfpzz) {
                return officialDealInvoiceService.dealDzfpResult(transactionFlowMerge, wkpFlowList, datasource, downloadVO);
            }
        } catch (BusinessException be) {
            log.error("{}出现业务异常，redisLockKey为：{}, code={}, msg={}", LOG_MSG,redisLockKey, be.getCode(), be.getMsg());
            throw new BusinessException(be.getCode(), be.getMsg());
        } catch (Exception ex) {
            log.error("{}出现未知异常，redisLockKey为：{}", LOG_MSG,redisLockKey, ex);
            throw new BusinessException(ResponseEnum.ERROR);
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
                log.info("{}redisson释放锁成功，redisLockKey为：{}", LOG_MSG, redisLockKey);
            } else {
                log.error("{}redisson释放锁失败，redisLockKey为：{}", LOG_MSG, redisLockKey);
            }
        }
        log.error("官网开票-下载发票接口，未调用数电票，也未调用电子发票，直接返回空结果，入参：{}", bo);
        return Result.OK();
    }

    /**
     * * ②根据交易日期，合并交易流水数据，合并后，校验JYRMBJE字段：
     *     如果JYRMBJE=0,则 7001 流水已抵消无需开票！
     *     如果JYRMBJE<0，则提示 7002 原流水已开票，请到柜台处理！
     * @param transactionFlowMerge
     * @param wkpFlowList
     */
    public  void dealJYRMBJE(TransactionFlowVO transactionFlowMerge, List<TransactionFlowVO> wkpFlowList) {
        List<Long> wkpRdids = wkpFlowList.stream().map(TransactionFlowVO::getRDID).collect(Collectors.toList());
        if (transactionFlowMerge.getJYRMBJE().compareTo(new BigDecimal("0")) == 0) {
            nvatTrandtadvaltaxsepService.updateLsztByRdids(0, wkpRdids, 1, false);
            throw new BusinessException(ResponseEnum.OFFICIAL_DZFPPT_OFFSET_ERROR);
        } else if (transactionFlowMerge.getJYRMBJE().compareTo(new BigDecimal("0")) < 0) {
            throw new BusinessException(ResponseEnum.OFFICIAL_DZFPPT_HAS_INVOICE_ERROR);
        }
    }

    /**
     * 校验接入账号
     * @param jrzh
     * @param jrmm
     * @return
     */
    private CommonEnum validJrzhJrmm(String jrzh, String jrmm) {
        String jymmConfig = interfacesProperties.getDzfp().get(jrzh);
        if (jrmm.equals(jymmConfig)) {
            if (jrzh.contains("guanwang")) {
                return CommonEnum.DATA_SOURCE_2;
            } else {
                // TODO 其他渠道待增加
                throw new BusinessException(ResponseEnum.OFFICIAL_JRZH_ERROR);
            }
        }
        throw new BusinessException(ResponseEnum.OFFICIAL_JRZH_ERROR);
    }



    /**
     * 处理已开票的交易流水，返回已开发票信息列表
     * @param ykpFlowList
     * @return
     */
    private List<InvoiceInfoVO> dealYkpFlowList (List<TransactionFlowVO> ykpFlowList) {
        // 根据流水id，查询发票信息
        Map<Long, TransactionFlowVO> ykpFlowMap = ykpFlowList.stream().collect(Collectors.toMap(TransactionFlowVO::getRDID, f -> f));
        List<InvoiceInfoVO> invoiceInfoList = nvatOutinvoicedetailsService.queryInvoiceBYRdids(new ArrayList<>(ykpFlowMap.keySet()));
        if (CollectionUtil.isEmpty(invoiceInfoList)) {
            // 不存在发票信息，非正常逻辑数据，不能开票，当做纸质票返回
            return null;
        }
        // 查询待开票信息，如果存在待开票，则返回错误码，不得开票
        List<InvoiceInfoVO> dkpInvoiceList = invoiceInfoList.stream()
                .filter(vo -> StringUtil.isEmpty(vo.getFPHM()) && StringUtil.isEmpty(vo.getFPDM()))
                .collect(Collectors.toList());

        if (CollectionUtil.isNotEmpty(dkpInvoiceList)) {
            // 返回错误码，不得开票
            throw new BusinessException(ResponseEnum.OFFICIAL_DAIKAIPIAO_ERROR);
        }

        List<InvoiceInfoVO> ykpInvoiceList = invoiceInfoList.stream()
                .filter(vo -> {
                    if (vo.getFPLXDM().equals(CommonEnum.INVOICE_TYPE_01.getKey()) || vo.getFPLXDM().equals(CommonEnum.INVOICE_TYPE_02.getKey())) {
                        return StringUtil.isNotEmpty(vo.getFPHM());
                    } else {
                        return StringUtil.isNotEmpty(vo.getFPHM()) && StringUtil.isNotEmpty(vo.getFPDM());
                    }
                }).collect(Collectors.toList());
        return ykpInvoiceList;
    }
    /**
     * 根据交易日期合并金额等数据
     * @param wkpFlowList
     * @return
     */
    private TransactionFlowVO getTransactionFlowMerge(List<TransactionFlowVO> wkpFlowList) {
        // * ②根据交易日期，合并交易流水数据，合并后，校验JYRMBJE字段：
        //      如果JYRMBJE=0,则 7001 流水已抵消无需开票！
        //      如果JYRMBJE<0，则提示 7002 原流水已开票，请到柜台处理！
        List<TransactionFlowVO> wkpFlowMergeList = wkpFlowList.stream().collect(Collectors.groupingBy(TransactionFlowVO::getJYRQ))
                .values().stream().map(v -> {
                    TransactionFlowVO flow = new TransactionFlowVO();
                    BeanUtils.copyProperties(v.get(0), flow);

                    flow.setRDID(v.stream().mapToLong(TransactionFlowVO::getRDID).max().getAsLong());
                    flow.setJYJE(v.stream().map(TransactionFlowVO::getJYJE).reduce(BigDecimal.ZERO, BigDecimal::add));
                    flow.setJYRMBJE(v.stream().map(TransactionFlowVO::getJYRMBJE).reduce(BigDecimal.ZERO, BigDecimal::add));
                    flow.setBHSJE(v.stream().map(TransactionFlowVO::getBHSJE).reduce(BigDecimal.ZERO, BigDecimal::add));
                    flow.setWKPJE(v.stream().map(TransactionFlowVO::getWKPJE).reduce(BigDecimal.ZERO, BigDecimal::add));
                    flow.setXXSE(v.stream().map(TransactionFlowVO::getXXSE).reduce(BigDecimal.ZERO, BigDecimal::add));
                    String kpbz = "交易日期:" + flow.getBZRQ();;
                    if (v.size() == 1) {
                        String bz = flow.getBZ();
                        byte[] bytes = (kpbz + bz).getBytes();
                        if (bytes.length<=130) {
                            kpbz += bz;
                        }
                    }
                    flow.setKpbz(kpbz);
                    return flow;
                }).collect(Collectors.toList());
        return wkpFlowMergeList.get(0); // 开票接口，入参交易日期只有1个
    }

    /**
     * 同一天的数据，若流水的开票标识不一样，开票标识=2的单独处理，其他数据当天的开票标识置为0, 且数据合并
     * @param resultMap
     */
    private void mergeJyrqData(Map<Date,Map<String,InvoiceQueryVO>> resultMap) {
        Set<Date> dates = resultMap.keySet();
        for (Date d : dates) {
            Map<String,InvoiceQueryVO> m = resultMap.get(d);

            if (m.get("0") == null) {
                continue;
            }
            // 过滤 开票标识=2 的数据
            List<InvoiceQueryVO> collect = m.entrySet().stream().filter(v -> !v.getKey().equals("2")).map(v -> v.getValue()).collect(Collectors.toList());
            if (CollectionUtil.isEmpty(collect)) {
                continue;
            }

            BigDecimal jyje = new BigDecimal(0);
            List<InvoiceQueryVO.Product> cpxxList = new ArrayList<>();
            for (InvoiceQueryVO vo : collect) {
                jyje = jyje.add(vo.getJyje());
                Map<String, InvoiceQueryVO.Product> cpMap = cpxxList.stream().collect(Collectors.toMap(c -> c.getCpdm(), c -> c));
                for (InvoiceQueryVO.Product p : vo.getCpxxList()) {
                    if (cpMap.get(p.getCpdm()) == null) {
                        cpxxList.add(p);
                    }
                }
            }

            InvoiceQueryVO v = new InvoiceQueryVO();
            v.setKpbs("0");
            v.setYwbh(collect.get(0).getYwbh());
            v.setTbrmc(collect.get(0).getTbrmc());
            v.setJyrq(collect.get(0).getJyrq());
            v.setDzfpXzdz(null);
            v.setSdpXzdzList(null);
            v.setJyje(jyje);
            v.setCpxxList(cpxxList);

            // 合并后的数据
            Map<String,InvoiceQueryVO> newMap = new HashMap<>();
            newMap.put("0", v);
            if (m.get("2") != null) {
                newMap.put("2", m.get("2"));
            }
            resultMap.put(d, newMap);
        }
    }
    private void convertToInvoiceQueryVO(Map<Date,Map<String,InvoiceQueryVO>> resultMap,
                                         InvoiceInfoVO infoVO, InvoiceFlowQueryVO flowVO, String dzfpurl, String nsrsbh) {
        Map<String, InvoiceQueryVO> queryMap = resultMap.computeIfAbsent(flowVO.getJYRQ(), k -> new HashMap<>());

        // 开票标识 = 0
        if (infoVO == null || flowVO.getLSZT().equals(1)) {
            convertVO(queryMap, "0", flowVO);
            return;
        } else if (infoVO.getFPLXDM().equals(CommonEnum.INVOICE_TYPE_026.getKey()) && StringUtils.isBlank(dzfpurl)) {
            convertVO(queryMap, "0", flowVO);
            return;
        }

        // 处理电子发票, 开票标识 = 1
        if (infoVO.getFPLXDM().equals(CommonEnum.INVOICE_TYPE_026.getKey()) && flowVO.getLSZT().equals(3)) {
            if(StringUtil.isBlank(nsrsbh)){
                throw new BusinessException(ResponseEnum.OFFICIAL_NO_AUTH_ERROR1);
            }
            InvoiceQueryVO vo1 = convertVO(queryMap, "1", flowVO);
            if (vo1.getDzfpXzdz() == null) {
                Set<String> dzfpSet = new HashSet<>();
                dzfpSet.add(dzfpurl);
                vo1.setDzfpXzdz(dzfpSet);
            } else {
                vo1.getDzfpXzdz().add(dzfpurl);
            }
            return;
        }

        // 处理纸质发票 开票标识 = 2
        if (infoVO.getFPLXDM().equals(CommonEnum.INVOICE_TYPE_004.getKey()) || infoVO.getFPLXDM().equals(CommonEnum.INVOICE_TYPE_007.getKey())) {
            if (flowVO.getLSZT().equals(3) ) {
                convertVO(queryMap, "2", flowVO);
            }
        }

        // 处理数电发票
        if (infoVO.getFPLXDM().equals(CommonEnum.INVOICE_TYPE_01.getKey()) || infoVO.getFPLXDM().equals(CommonEnum.INVOICE_TYPE_02.getKey())) {
            if (flowVO.getLSZT().equals(3) ) {
                InvoiceQueryVO vo4 = convertVO(queryMap, "1", flowVO);
//                SdpXzdzVO dz = this.getSdpXzdzVO(infoVO.getFPHM());
                SdpXzdzVO dz = OfficialServiceCommonMtd.getSdpXzdzVO(infoVO.getFPHM(), interfacesProperties.getSdpDownloadUrlPrefix(), sm4Properties.getKey().getBytes());
                if (vo4.getSdpXzdzList() == null) {
                    List<SdpXzdzVO> sdpXzdzList = new ArrayList<>();
                    sdpXzdzList.add(dz);
                    vo4.setSdpXzdzList(sdpXzdzList);
                } else {
                    vo4.getSdpXzdzList().add(dz);
                }
            }
        }
    }

    private InvoiceQueryVO convertVO(Map<String, InvoiceQueryVO> queryMap, String kpbs, InvoiceFlowQueryVO flowVO) {
        InvoiceQueryVO vo = new InvoiceQueryVO();
        vo.setJyrq(flowVO.getJYRQ());
        vo.setTbrmc(flowVO.getKFHM());
        vo.setYwbh(flowVO.getYWBH());

        InvoiceQueryVO.Product p = new InvoiceQueryVO.Product();
        p.setCpdm(flowVO.getCPDM());
        p.setCpmc(flowVO.getCPMC());

        InvoiceQueryVO result = queryMap.computeIfAbsent(kpbs, k -> vo);
        result.setJyje(result.getJyje() == null ? flowVO.getJYJE() : result.getJyje().add(flowVO.getJYJE()));
        result.setKpbs(kpbs);
        if (result.getCpxxList() == null) {
            List<InvoiceQueryVO.Product> cpxxList = new ArrayList<>();
            cpxxList.add(p);
            result.setCpxxList(cpxxList);
        } else {
            Map<String, InvoiceQueryVO.Product> cpMap = result.getCpxxList().stream().collect(Collectors.toMap(v -> v.getCpdm(), v -> v));
            if (cpMap.get(p.getCpdm()) == null) {
                result.getCpxxList().add(p);
            }
        }
        return result;
    }

}
